package org.dfl.core.model.transitions;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.dfl.core.data.types.Type;
import org.dfl.core.data.types.TypeManager;
import org.dfl.core.model.TransitionExecutionException;
import org.dfl.core.model.XMLLoaderException;
import org.dfl.messages.Messages;
import org.jdom.Element;


/**
 * Transition to fire shell commands
 * 
 * each input is added as a command line argument
 * @author Piotr Wlodarczyk
 *
 */
public class ExecTransition extends MultipleInputsTransition {
	private String dir;	// directory to run the command in
	private String command;	// command to run
	
	@Override
	protected int getDefaultMaxInputs() {
		return 25;
	}

	@Override
	protected int getDefaultMinInputs() {
		return 0;
	}
	
	public String getCommand() {
		return command;
	}

	public void setCommand(String command) {
		this.command = command;
	}

	public String getDir() {
		return dir;
	}

	public void setDir(String dir) {
		this.dir = dir;
	}

	@Override
	public List<String> getFreeInputs(Type type) {
		Set<String> keys = getInputsDefinition().keySet();
		List<String> ret = new ArrayList<String>();
		for(int i=1;i<=25;i++){
			ret.add(getKeyName(i));
		}
		ret.removeAll(keys);
		return ret;
	}
	
	private String getKeyName(int i){
		return "arg"+(i<10?"0":"")+i; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
	}
	
	public List<String> divideCommand(String cmd){
		List<String> res = new ArrayList<String>();
		int parI2 =-1;
		int parI1 = cmd.indexOf("\""); //$NON-NLS-1$
		if(parI1>=0)parI2 = cmd.indexOf("\"",parI1+1);  //$NON-NLS-1$
			
		if(parI1 >=0 && parI2 >=0 ){
			res.addAll(divideCommand(cmd.substring(0, parI1)));
			String el = cmd.substring(parI1+1,parI2);
			el = el.trim();
			if(!"".equals(el)) res.add(el); //$NON-NLS-1$
			res.addAll(divideCommand(cmd.substring(parI2+1)));
		}else{
			String[] args = cmd.split("\\s"); //$NON-NLS-1$
			for(String arg : args){
				if(!arg.trim().equals("")){ //$NON-NLS-1$
					res.add(arg.trim());
				}
			}
		}
		return res;
	}
	
	@Override
	protected Object fire(Map<String, Object> inputMap) throws TransitionExecutionException {
		StringBuffer res = new StringBuffer();
		try {
			List<String> args = new ArrayList<String>();
			args.addAll(divideCommand(command));
			
			for(int i=1;i<=25;i++){
				if(inputMap.containsKey(getKeyName(i))){
					args.add(inputMap.get(getKeyName(i)).toString());
				}
			}
			
			File f = null;
			if(dir!=null && !dir.trim().equals("")){ //$NON-NLS-1$
				f = new File(dir);
			}
			String line;
			Runtime runtime = Runtime.getRuntime();
			
//			System.out.println(args);
//			System.out.println(f);
//			if(true) return "aaa";
			
			String[] argsTab = new String[args.size()];
			argsTab = args.toArray(argsTab);
			Process p = runtime.exec(argsTab,new String[0],f);
			
			BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
			while ((line = input.readLine()) != null) {
				res.append(line);
			}
			input.close();
		} catch (Exception e) {
			throw new TransitionExecutionException(e);
		}

		return res.toString();
	}

	@Override
	public String getDefaultDescription() {
		return Messages.ExecTransition_description+(command==null?"":": "+command); //$NON-NLS-2$ //$NON-NLS-3$
	}

	@Override
	protected Type getDefaultOutputDefinition() {
		return TypeManager.getStringType();
	}

	@Override
	public boolean isUserInitationNeeded() {
		return (command==null || command.trim().equals("")); //$NON-NLS-1$
	}
	
	@Override
	public void load(Element elem) throws XMLLoaderException {
		super.load(elem);
		if(elem.getChild("toolspecific") != null){ //$NON-NLS-1$
			setCommand(elem.getChild("toolspecific").getChildText("command",Transition.toolspecificNS)); //$NON-NLS-1$ //$NON-NLS-2$
			setDir(elem.getChild("toolspecific").getChildText("startDir",Transition.toolspecificNS)); //$NON-NLS-1$ //$NON-NLS-2$
		}
	}
	
	@Override
	public Element save() {
		Element elem = super.save();
		
		Element toolspecificElem = elem.getChild("toolspecific"); //$NON-NLS-1$
		if(toolspecificElem == null){
			toolspecificElem = new Element("toolspecific"); //$NON-NLS-1$
			toolspecificElem.setAttribute("tool",""); //$NON-NLS-1$ //$NON-NLS-2$
			toolspecificElem.setAttribute("version",""); //$NON-NLS-1$ //$NON-NLS-2$
			elem.addContent(toolspecificElem);
		}
		
		Element commandElem = new Element("command",Transition.toolspecificNS); //$NON-NLS-1$
		commandElem.setText(getCommand());
		toolspecificElem.addContent(commandElem);
		
		Element dirElem = new Element("startDir",Transition.toolspecificNS); //$NON-NLS-1$
		dirElem.setText(getDir());
		toolspecificElem.addContent(dirElem);
		
		return elem;
	}
}
